package com.cll.learn.rpc.provider.context;

import com.cll.learn.rpc.common.coder.RpcDecoder;
import com.cll.learn.rpc.common.coder.RpcResponseEncoder;
import com.cll.learn.rpc.common.dto.RpcRequest;
import com.cll.learn.rpc.common.dto.RpcResponse;
import com.cll.learn.rpc.common.serializer.JsonSerializable;
import com.cll.learn.rpc.common.serializer.ProtostuffSerializable;
import com.cll.learn.rpc.provider.handler.RpcProviderHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 描述信息:
 * 服务端的启动
 * @author CLL
 * @version 1.0
 * @date 2020/9/14 15:50
 */
public class RpcProvider {

    private static final Logger logger = LoggerFactory.getLogger(RpcProvider.class);

    /**
     * 启动服务端
     * @param ip    监听地址
     * @param port  监听的端口号
     */
    public static void startServer(String ip, int port) throws InterruptedException {
        logger.info("===>>> startServer");
        // 处理连接的组
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // 处理请求的组
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        // 服务端启动配置类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        /*
        为acceptor(接收方)和client(客户端)设置EventLoopGroup.
        这两个EventLoopGroup负责处理ServerChannel和所有Channel的请求事件和IO读写
         */
        serverBootstrap.group(bossGroup, workerGroup)
                // 指定用于从中创造通道实例的类，就是指定创造的通道的类型
                .channel(NioServerSocketChannel.class)
                /*
                    childHandler:设置 用于为通道的请求 提供服务 的ChannelHandler
                    ChannelInitializer:一种特殊的通道入站处理适配器，提供了一次在Channel通道注册到EventLoop的时候进行初始化的操作。
                 */
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 获取acceptor的通道之间的管道
                        ChannelPipeline pipeline = ch.pipeline();
                        /*
                        因为接收到的是RpcRequest类型的数据，所以在数据入站的时候，
                        需要针对RpcRequest类型的数据进行解码
                         */
                        pipeline.addLast(new RpcDecoder(RpcRequest.class, new ProtostuffSerializable()));
                        /*
                        数据出战到下一个byteBuf接收，所以肯定需要先进行编码
                         */
                        pipeline.addLast(new RpcResponseEncoder(RpcResponse.class, new ProtostuffSerializable()));
                        /*
                        添加自定义的通道事件处理器
                         */
                        pipeline.addLast(new RpcProviderHandler());

                    }
                });
        serverBootstrap.bind(ip, port).sync();
        logger.info("===>>> 服务端启动成功.ip = {}, port = {}", ip, port);
    }
}
